#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>

#include "estructuras.h"
#include "constantes.h"
#include "log.h"
#include "sockets.h"
#include "configuracion.h"
#include "estadisticas.h"
#include "listas.h"
#include "NIPC.h"

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;

extern chs glChs;
extern float RPM;
extern int ALG;
extern int MODO;
extern char *data;
extern int sectores_totales_vda;
extern t_log *logFile;
int activaEnAtencion;

void * AtenderPedido (void *args); 

void * AtenderPedido (void *args)
{
	int *pSocketConectado;
	sectoresIntermedios listaSectoreYTiempos;
	int f,i,payload,j;
	int ret;
	int sectoresEscritos=0;
	char sAux[20];
	char cadAux[20];
	char time[10];
	int traceon=0;
	struct sockaddr_un remote;
	int len;
	char sPosicionCabezal[10];
	colas2 *q = (colas2 *) args;
	
	sem_init(&pedidos, 0, 0);
	while(1)
	{		
		
		/*sem_wait(&pedidos); */
		if(!(estaVacia(q->activacabeza))){
			
			if(ALG==2)
				activaEnAtencion=1;
			
			struct ListaIDdescriptors * nodoaAtender;
		
			if(pthread_mutex_lock(&mutex)!=0){
					perror("pthread_mutex_unlock");
					exit(EXIT_FAILURE);
			}
		
			nodoaAtender=SacarNodoDescriptoresDeLista(&q->activacabeza,&q->activacola,&q->segundaPasadaActiva);
			
			if(pthread_mutex_unlock(&mutex)!=0){
					perror("pthread_mutex_unlock");
					exit(EXIT_FAILURE);
			}
			
			/*TRACE*/
			log_info(logFile, "TRACE", "SECTORES Y TIEMPOS");	
			log_info(logFile, "TRACE", "POSICION CABEZAL:%i",posicionCabezal);
			log_info(logFile, "TRACE", "SECTOR SOLICITADO:%i",nodoaAtender->sector);
			listaSectoreYTiempos = SectoresIntermedios(posicionCabezal,nodoaAtender->sector,glChs,RPM);
			log_info(logFile, "TRACE", "SECTORES RECORRIDOS:");
			for( f = 0;f < listaSectoreYTiempos.tamanioVector;f++)
			{
				log_info(logFile,"TRACE","%d", listaSectoreYTiempos.ptrSectoresLeidos[f]);
			}
			log_info(logFile,"TRACE","TIEMPO CONSUMIDO:%f ms",listaSectoreYTiempos.tiempoDeAcceso);
			
			memset(sAux,'\0',20);
			intacad(nodoaAtender->sector, sAux);	
			
			
			if((nodoaAtender->operacion == 4))
			{
				
				if((buscarTrace(nodoaAtender->sector)==1))
				{
					traceon=1;
					payload=RTA_TRACE;
				}
				else
				{
					traceon=0;
					payload=FIN_TRACE;
				}	
				
				sleep(0.001);
				
				char* trace=(char *)malloc(sizeof(char)*2);
				strcpy(trace,"");
				printf("\n");
				for(f=0;f < listaSectoreYTiempos.tamanioVector;f++)
				{		
					intacad(listaSectoreYTiempos.ptrSectoresLeidos[f],cadAux);
					trace = (char*) realloc(trace,strlen(trace)+strlen(cadAux)+1);
					sprintf(trace,"%s%s",trace,cadAux);
					if(f!=listaSectoreYTiempos.tamanioVector-1)
					{	
						trace = (char*) realloc(trace,strlen(trace)+2);					
						sprintf(trace,"%s,",trace);
					}	
				}
			
				sprintf(time,"%f",listaSectoreYTiempos.tiempoDeAcceso);	
				
				
				/*Le envio a la consola la posicion del cabezal*/
				InfoIPC rInfoIPC38;
				intacad(posicionCabezal,sPosicionCabezal);
				rInfoIPC38.payLoadLength= strlen(sPosicionCabezal) + 1;	
				generarStructIPC(sPosicionCabezal ,payload,&rInfoIPC38);
				enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC38);
				free(rInfoIPC38.payload);
				/*Le envio a la consola el numero de sector respondido*/
				InfoIPC rInfoIPC39;
				rInfoIPC39.payLoadLength= strlen(sAux) + 1;	
				generarStructIPC(sAux ,payload,&rInfoIPC39);
				enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC39);
				free(rInfoIPC39.payload);
				/*Le envio a la consola el recorrido*/
				InfoIPC rInfoIPC40;
				rInfoIPC40.payLoadLength=strlen(trace)+1;	
				generarStructIPC(trace,payload,&rInfoIPC40);
				enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC40);
				free(trace);
				free(rInfoIPC40.payload);
				/*Le envio a la consola el tiempo*/
				InfoIPC rInfoIPC41;
				rInfoIPC41.payLoadLength= strlen(time) + 1;	
				generarStructIPC(time,payload,&rInfoIPC41);
				enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC41);
				free(rInfoIPC41.payload);
				
				
			}
			
			
			if((nodoaAtender->operacion == 0)||(nodoaAtender->operacion == 2))
			{
				char *auxread=(char *)malloc(512);
				memset(auxread,'\0',512);
				readSector(nodoaAtender->sector,&auxread);
				
				if((nodoaAtender->operacion == 0)||(nodoaAtender->operacion == 4)){
					payload=RTA_READ_SECTOR_REQUEST;					
					
				}	
				else{
					payload=RTA_READ_SECTORSYNC_REQUEST;
					printf("Leer SectorSYNC: %i \n", nodoaAtender->sector);
				}
				
				
				if(MODO==1)
				{
					
					int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1 + 512 +1;
					char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
					memset(buffer,'\0',tamanio_buff);
					strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
					strcat(buffer, ",");
					strcat(buffer, sAux);
					strcat(buffer, ";");
					
					memcpy(buffer + strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 1, auxread, 512); 
					
					InfoIPC rInfoIPC3;
					rInfoIPC3.payLoadLength=tamanio_buff;
					generarStructIPC(buffer,payload,&rInfoIPC3);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);	
					
					free(rInfoIPC3.payload);
					free(buffer);
					
					sectoresEscritos++;
					
					if(sectoresEscritos%100000==0)
						printf("Se leyeron %i \n",sectoresEscritos);
						
					log_info(logFile, "CONNECT", "SE RESPONDIO PEDIDO.\nTipo:Lectura\nSector: %s", sAux);	
					
				}
				else{
					
					/*Le envio al cliente FSS el numero de sector respondido*/
					InfoIPC rInfoIPC3;
					rInfoIPC3.payLoadLength= strlen(sAux) + 1;
					generarStructIPC(sAux ,payload,&rInfoIPC3);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC3);
					
					free(rInfoIPC3.payload);
			
					
					/*Le envio al cliente FSS la data correspondiente*/
					InfoIPC rInfoIPC4;
					rInfoIPC4.payLoadLength=512;
					generarStructIPC(auxread,payload,&rInfoIPC4);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC4);				
				
					free(rInfoIPC4.payload);
					
					log_info(logFile, "LISTEN", "SE RESPONDIO PEDIDO.\nTipo:Lectura\nSector: %s", sAux);		
				}
				
				free(auxread);
				
			}
			if((nodoaAtender->operacion == 1)||(nodoaAtender->operacion == 3)||(nodoaAtender->operacion == 5))
			{
				

				if((nodoaAtender->operacion == 1)||(nodoaAtender->operacion == 5)){
					printf("Escribir Sector: %i - %s\n", nodoaAtender->sector, nodoaAtender->data);	
					payload=RTA_WRITE_SECTOR_REQUEST;
				}	
				
				if(nodoaAtender->operacion == 3)
				{
					sectoresEscritos++;
					printf("Escribir SectorSYNC: %i \n", nodoaAtender->sector);
					payload=RTA_WRITE_SECTORSYNC_REQUEST;
				}
				
				writeSector(nodoaAtender->sector, nodoaAtender->data);
				
				if(MODO==1){
				
					
					if(nodoaAtender->operacion == 1){
	
						int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 2 ;
						char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
					
						strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
						strcat(buffer, ",");
						strcat(buffer, sAux);
						strcat(buffer, ";");
						
						InfoIPC rInfoIPC6;
						rInfoIPC6.payLoadLength=tamanio_buff;
						generarStructIPC(buffer,payload,&rInfoIPC6);
						enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC6);	
						
						
						free(rInfoIPC6.payload);
						free(buffer);
					}	
					if(nodoaAtender->operacion == 3){
					
						if(sectoresEscritos%100000==0)
							printf("Se sincronizaron %i \n",sectoresEscritos);
			
						if(sectoresEscritos%1000==0)
							msync(data+sectoresEscritos*512,512*1000, MS_SYNC);
						
						
						if(sectoresEscritos==sectores_totales_vda){
						
							msync(data+(sectores_totales_vda - sectores_totales_vda%1000)*512,512*(sectores_totales_vda%1000), MS_SYNC);
							int tamanio_buff = strlen(nodoaAtender->sDescriptorID_delPedido) + 1 + strlen(sAux) + 2 ;
							char *buffer = (char *) malloc (sizeof(char) * tamanio_buff);
						
							strcpy(buffer, nodoaAtender->sDescriptorID_delPedido);
							strcat(buffer, ",");
							strcat(buffer, sAux);
							strcat(buffer, ";");
							
							InfoIPC rInfoIPC6;
							rInfoIPC6.payLoadLength=tamanio_buff;
							printf("A punto de enviar FINSINCRO \n");
							generarStructIPC(buffer,FINSINCRO,&rInfoIPC6);
							/**
							strcpy(rInfoIPC6.payLoadDescriptor,nodoaAtender->sDescriptorID_delPedido);
							**/
							enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC6);	
							
							buffer=rInfoIPC6.payload;
							free(buffer);
							
						}	
					}
					
					log_info(logFile, "CONNECT", "SE RESPONDIO PEDIDO.\nTipo:Escritura\nSector: %s", sAux);
					
				}
				else{
					InfoIPC rInfoIPC5;
					rInfoIPC5.payLoadLength= strlen(sAux) + 1;
					generarStructIPC(sAux,payload,&rInfoIPC5);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC5);
					free(rInfoIPC5.payload);
					
					log_info(logFile, "LISTEN", "SE RESPONDIO PEDIDO.\nTipo:Escritura\nSector: %s", sAux);
				}
			}
			
			if((nodoaAtender->operacion == 0)||(nodoaAtender->operacion == 1)||(nodoaAtender->operacion == 2)||(nodoaAtender->operacion == 3))
			{
			
				if(traceon){
				
					payload=RTA_TRACE;
					char* trace=(char *)malloc(sizeof(char)*2);
					strcpy(trace,"");
					printf("\n");
					for(f=0;f < listaSectoreYTiempos.tamanioVector;f++)
					{		
						intacad(listaSectoreYTiempos.ptrSectoresLeidos[f],cadAux);
						trace = (char*) realloc(trace,strlen(trace)+strlen(cadAux)+1);
						sprintf(trace,"%s%s",trace,cadAux);
						if(f!=listaSectoreYTiempos.tamanioVector-1)
						{	
							trace = (char*) realloc(trace,strlen(trace)+2);					
							sprintf(trace,"%s,",trace);
						}	
					}
				
					sprintf(time,"%f",listaSectoreYTiempos.tiempoDeAcceso);	
					
					/*Le envio a la consola la posicion del cabezal*/
					InfoIPC rInfoIPC38;
					intacad(posicionCabezal,sPosicionCabezal);
					rInfoIPC38.payLoadLength= strlen(sPosicionCabezal) + 1;	
					generarStructIPC(sPosicionCabezal ,payload,&rInfoIPC38);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC38);
					free(rInfoIPC38.payload);
					/*Le envio a la consola el numero de sector respondido*/
					InfoIPC rInfoIPC39;
					rInfoIPC39.payLoadLength= strlen(sAux) + 1;	
					generarStructIPC(sAux ,payload,&rInfoIPC39);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC39);
					free(rInfoIPC39.payload);
					/*Le envio a la consola el recorrido*/
					InfoIPC rInfoIPC40;
					rInfoIPC40.payLoadLength=strlen(trace)+1;	
					generarStructIPC(trace,payload,&rInfoIPC40);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC40);
					free(trace);
					free(rInfoIPC40.payload);
					/*Le envio a la consola el tiempo*/
					InfoIPC rInfoIPC41;
					rInfoIPC41.payLoadLength= strlen(time) + 1;	
					generarStructIPC(time,payload,&rInfoIPC41);
					enviarIPC(atoi(nodoaAtender->sSocketPorElCualResponder),&rInfoIPC41);
					free(rInfoIPC41.payload);
				}	
			}	
		
			
			posicionCabezal=nodoaAtender->sector + 1;		
			
			//free(nodoaAtender);
			
		}
		else{
			
			if(ALG==2){
				if(!(estaVacia(q->pasivacabeza))){
					
					if(pthread_mutex_lock(&mutex2)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					if(pthread_mutex_lock(&mutex)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					
					activaEnAtencion=0;
					q->activacabeza=q->pasivacabeza;
					q->pasivacabeza=NULL;
					
					if(pthread_mutex_unlock(&mutex)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}
					if(pthread_mutex_unlock(&mutex2)!=0){
						perror("pthread_mutex_lock");
						exit(EXIT_FAILURE);
					}			
				}
			}
		}
	}	
	
}
